namespace WP7Contrib.Services.BingMaps.Model
{
    using System;
    using Common;

    public class Address : BaseModel, IEquatable<Address>, ICloneable<Address>
    {
        public static Address Empty { get { return new Address(); } }

        private string addressLine;
        private string adminDistrict;
        private string countryRegion;
        private string formattedAddress;
        private string locality;
        private string postalCode;
        private Confidence confidence;

        public string AddressLine
        {
            get
            {
                return this.addressLine;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.addressLine, value, () => this.AddressLine);
            }
        }

        public bool HasAddressLine
        {
            get { return !string.IsNullOrEmpty(this.addressLine); }
        }

        public string AdminDistrict
        {
            get
            {
                return this.adminDistrict;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.adminDistrict, value, () => this.AdminDistrict);
            }
        }

        public bool HasAdminDistrict
        {
            get { return !string.IsNullOrEmpty(this.adminDistrict); }
        }

        public string CountryRegion
        {
            get
            {
                return this.countryRegion;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.countryRegion, value, () => this.CountryRegion);
            }
        }

        public bool HasCountryRegion
        {
            get { return !string.IsNullOrEmpty(this.countryRegion); }
        }
        
        public string FormattedAddress
        {
            get
            {
                return this.formattedAddress;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.formattedAddress, value, () => this.FormattedAddress);
            }
        }

        public bool HasFormattedAddress
        {
            get { return !string.IsNullOrEmpty(this.formattedAddress); }
        }

        public string Locality
        {
            get
            {
                return this.locality;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.locality, value, () => this.Locality);
            }
        }

        public string PostalCode
        {
            get
            {
                return this.postalCode;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.postalCode, value, () => this.PostalCode);
            }
        }

        public bool HasPostalCode
        {
            get { return !string.IsNullOrEmpty(this.postalCode); }
        }
        
        public Confidence Confidence
        {
            get
            {
                return this.confidence;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.confidence, value, () => this.Confidence);
            }
        }
        
        public static bool operator ==(Address a1, Address a2)
        {
            return Equals(a1, a2);
        }

        public static bool operator !=(Address a1, Address a2)
        {
            return !Equals(a1, a2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is Address && this.Equals((Address)obj);
        }

        public override int GetHashCode()
        {
            return this.CombineHashCodes(this.AddressLine,
                                         this.AdminDistrict,
                                         this.Confidence,
                                         this.CountryRegion,
                                         this.FormattedAddress,
                                         this.Locality,
                                         this.PostalCode);
        }

        public bool Equals(Address address)
        {
            if (ReferenceEquals(null, address))
            {
                return false;
            }

            if (this.AddressLine != address.AddressLine)
            {
                return false;
            }

            if (this.AdminDistrict != address.AdminDistrict)
            {
                return false;
            }

            if (this.Confidence != address.Confidence)
            {
                return false;
            }

            if (this.CountryRegion != address.CountryRegion)
            {
                return false;
            }

            if (this.FormattedAddress != address.FormattedAddress)
            {
                return false;
            }

            if (this.Locality != address.Locality)
            {
                return false;
            }

            if (this.PostalCode != address.PostalCode)
            {
                return false;
            }

            return true;
        }

        public Address ShallowClone()
        {
            return this.DeepClone();
        }

        public Address DeepClone()
        {
            var address = new Address
            {
                AddressLine = this.AddressLine,
                AdminDistrict = this.AdminDistrict,
                Confidence = this.Confidence,
                CountryRegion = this.CountryRegion,
                FormattedAddress = this.FormattedAddress,
                Locality = this.Locality,
                PostalCode = this.PostalCode
            };

            return address;
        }
    }
}